<template>
  <div class="page">
    <main-card :title="title" :loading="loading || isForecastLoading" :show-screen-space="false" :crumbs="crumbs">
      <div class="predicted-wrap">
        <div class="predicted-main">
          <upload-card :result-list="resultList" @on-file-change="onFileChange" />
          <div v-if="taskType === 'image' && resultList.length" class="result-list-wrap">
            <collapse-list default-show :result-list="resultList" />
          </div>
        </div>
        <div class="predicted-result">
          <result-card v-model:threshold-value="thresholdValue" :result-list="resultList" @change-threshold="changeThreshold" />
        </div>
      </div>
    </main-card>
  </div>
</template>

<script setup lang="ts">
  import { message } from 'ant-design-vue'
  import axios from 'axios'
  import { cloneDeep, debounce } from 'g6-fn'
  import { ref } from 'vue'
  import { computed } from 'vue'
  import { useRequest } from 'vue-request'
  import { useRoute, useRouter } from 'vue-router'

  import { modelTrainingApi } from '@/services/api'

  import { trainingSetDict } from '../options'
  import ResultCard from './components/ResultCard.vue'
  import UploadCard from './components/UploadCard.vue'

  const route = useRoute()
  const router = useRouter()
  const taskId = route.params.id as string

  export type TaskType = 'image' | 'object'
  let taskType = ref<TaskType>('image')
  const title = ref<any>('任务A')

  const crumbs = computed(() => {
    return [{ name: '模型训练', path: '/modal-training/list' }, { name: `预测任务（${title.value}）` }]
  })

  const loading = ref<boolean>(false)
  let algoApiUrl = ''
  /* 阈值 */
  const thresholdValue = ref(0)
  const changeThreshold = debounce((value: number) => {
    resultList.value = resultListCopy.filter((item: any) => item.value > value)
  }, 500)

  const resultList = ref<any[]>([])
  let resultListCopy: any[] = []
  const onFileChange = async (file: File) => {
    try {
      thresholdValue.value = 0
      resultList.value = []
      loading.value = true
      const { data } = await axios.post(
        algoApiUrl,
        { file },
        {
          headers: {
            'Content-Type': 'multipart/form-data'
          }
        }
      )
      if (data?.code !== 0) {
        return message.error('无法预测')
      }
      const dataList = data?.result || []
      resultList.value = taskType.value === 'image' ? resultToImageTask(dataList) : resultToObjectTask(dataList)
      resultListCopy = cloneDeep(resultList.value)
    } catch (error) {
      message.error('预测失败')
    } finally {
      loading.value = false
    }
  }

  /* 算法结果转目标检测 */
  const resultToObjectTask = (result: any[] = []) => {
    if (!result.length) {
      return []
    }
    const resultList = result.map((item: any, index: number) => {
      const label = trainingSetDict[item.classes]?.name
      const value = item.conf
      const box = item.box
      return { id: index, label, value, box }
    })
    return resultList
  }

  /* 算法结果转图像分类 */
  const resultToImageTask = (result: any[] = []) => {
    if (!result.length) {
      return []
    }
    const resultList = result.map((item: any, index: number) => {
      const label = trainingSetDict[item.class]?.name
      const value = item.probability
      return { id: index, label, value }
    })
    return resultList
  }

  const { loading: isForecastLoading, runAsync: runForecastTask } = useRequest<any>(modelTrainingApi.forecast)
  const init = async () => {
    try {
      const { data } = await runForecastTask(
        {},
        {
          urlParams: {
            id: taskId
          }
        }
      )
      title.value = data?.name
      taskType.value = data?.typeId === 1 ? 'image' : 'object'
      algoApiUrl = data?.url
    } catch (error) {
      router.replace('/modal-training/list')
    }
  }
  init()
</script>

<style lang="less" scoped>
  .page {
    .predicted-wrap {
      display: flex;
      width: 100%;
      height: 698px;
      background: #fff;
      border: 1px solid #e8e9eb;
      border-radius: 10px;

      .predicted-main {
        position: relative;
        width: 1016px;
        height: 100%;

        .result-list-wrap {
          position: absolute;
          top: 0;
          right: 0;
          width: 180px;
        }
      }

      .predicted-result {
        min-width: 0;
        flex: 1;
        height: 100%;
        border-left: 1px solid #e8e8eb;
      }
    }
  }
</style>
